package org.chenwang.projects.ehcacheaws;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
import org.jets3t.service.model.S3Bucket;
import org.jets3t.service.model.S3Object;
import org.jets3t.service.security.AWSCredentials;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.Status;

public class AmazonS3CacheReplicatorImplRestSimple extends
		AmazonS3CacheReplicator {
	
	private static final Log log = LogFactory.getLog(AmazonS3CacheReplicatorImplRestSimple.class);
	
	protected RestS3Service service;

	
	
	public AmazonS3CacheReplicatorImplRestSimple(String bucketName,
			String pathName, String pathSeparator, AWSCredentials credentials) {
		super(bucketName, pathName, pathSeparator, credentials);
		this.initService();
	}

	protected void initService() {
		try {
			this.service = new RestS3Service(this.credentials);
			log.debug("initialised underlying storage service");
		}
		catch (S3ServiceException s3se) {
			log.fatal("error happened when initialising underlying storage access!", s3se);
			this.service = null;
			this.status = Status.STATUS_UNINITIALISED;
		}
	}

	@Override
	public void notifyElementPut(Ehcache cache, Element element)
			throws CacheException {
		if (this.service != null) {

			try {
				S3Bucket b = new S3Bucket(this.bucketName);
				S3Object o = new S3Object(b, 
						this.generateKey(element), this.generateValue(element));
				this.service.putObject(b, o);
				log.debug("put element [" + element + "]");
			}
			catch (S3ServiceException s3se) {
				log.fatal("error happened when putting element [" + element + "] for cache [" + cache + "]!", s3se);
			}
			
		}
		else {
			log.warn("avoided putting element as underlying storage service is unavailable!");
		}
	}

	@Override
	public void notifyElementRemoved(Ehcache cache, Element element)
			throws CacheException {
		if (this.service != null) {

			try {
				this.service.deleteObject(this.bucketName, this.generateKey(element));
				log.debug("removed element [" + element + "]");
			}
			catch (S3ServiceException s3se) {
				log.fatal("error happened when removing element [" + element + "] for cache [" + cache + "]!", s3se);
			}
			
		}
		else {
			log.warn("avoided removing element as underlying storage service is unavailable!");
		}
	}

	@Override
	public void notifyElementUpdated(Ehcache cache, Element element)
			throws CacheException {
		if (this.service != null) {

			try {
				S3Bucket b = new S3Bucket(this.bucketName);
				S3Object o = new S3Object(b, 
						this.generateKey(element), this.generateValue(element));
				this.service.putObject(b, o);
				log.debug("updated element [" + element + "]");
			}
			catch (S3ServiceException s3se) {
				log.fatal("error happened when updating element [" + element + "] for cache [" + cache + "]!", s3se);
			}
			
		}
		else {
			log.warn("avoided updating element as underlying storage service is unavailable!");
		}
	}

	@Override
	public void notifyRemoveAll(Ehcache cache) {
		if (this.service != null) {
			for (Object o : cache.getKeys()) {
				try {
					String k = this.generateKey(o);
					this.service.deleteObject(this.bucketName, k);
					log.debug("removed element with key [" + k + "]");
				}
				catch (S3ServiceException s3se) {
					log.fatal("error happened when removing all elements for cache [" + cache + "]!", s3se);
				}
			}
			log.debug("all elements removed for cache [" + cache + "]");
		}
		else {
			log.warn("avoided removing all elements as underlying storage service is unavailable!");
		}
	}

	@Override
	public Object doClone() throws CloneNotSupportedException {
		return new AmazonS3CacheReplicatorImplRestSimple(this.bucketName, 
				this.pathName, this.pathSeparator, this.credentials);
	}

}
